package kd.xkqj.unittest.plugin;

import kd.xkqj.unittest.plugin.model.JavaFileInfo;
import kd.xkqj.unittest.plugin.model.JavaMethodInfo;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * @description: java文件转换器
 * @author feng_jun_peng
 * @create 2024-12-17 16:52 
 * @version 1.0
 */
public class JavaFileParser {

    /**
     * description: 读取.java文件的包名、类名、公有方法名
     * @author: feng_jun_peng
     * @create: 2024-12-17 16:56
     * @param filePath: java文件绝对路径
     * @return: kd.xkqj.unittest.plugin.model.JavaFileInfo
     */
    public static JavaFileInfo parseJavaFile(String filePath) {
        String packageName = null;
        String className = null;
        String superclass = null;
        List<JavaMethodInfo> publicMethods = new ArrayList<>();
        List<JavaMethodInfo> protectedMethods = new ArrayList<>();
        List<JavaMethodInfo> privateMethods = new ArrayList<>();

        // 正则表达式
        Pattern packagePattern = Pattern.compile("^\\s*package\\s+([a-zA-Z0-9_.]+)\\s*;");
        Pattern classPattern = Pattern.compile("^\\s*public\\s+class\\s+([a-zA-Z0-9_]+)\\s*(extends\\s+([a-zA-Z0-9_]+))?\\s*");
        Pattern publicMethodPattern = Pattern.compile("^\\s*public\\s+[^;]*\\s+([a-zA-Z0-9_]+)\\s*\\(.*\\)");
        Pattern protectedMethodPattern = Pattern.compile("^\\s*protected\\s+[^;]*\\s+([a-zA-Z0-9_]+)\\s*\\(.*\\)");
        Pattern privateMethodPattern = Pattern.compile("^\\s*private\\s+[^;]*\\s+([a-zA-Z0-9_]+)\\s*\\(.*\\)");


        int totalLine;
        try {
            int lineIndex = -1;
            int lastMethodType = 0; //匹配到上次方法的类型，1是公共，2是保护，3是私有

            var allLines = Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8);
            totalLine = allLines.size();
            for (var line : allLines) {
                lineIndex++;
                // 检查包名
                if (packageName == null) {
                    Matcher packageMatcher = packagePattern.matcher(line);
                    if (packageMatcher.find()) {
                        packageName = packageMatcher.group(1);
                    }
                }

                // 检查类名
                if (className == null) {
                    Matcher classMatcher = classPattern.matcher(line);
                    if (classMatcher.find()) {
                        className = classMatcher.group(1);
                        // 获取继承类
                        if (classMatcher.group(3) != null) {
                            superclass = classMatcher.group(3);
                        }
                    }
                }

                // 检查公共方法
                Matcher methodMatcher = publicMethodPattern.matcher(line);
                if (methodMatcher.find()) {
                    setLastMethodEndLine(lastMethodType, lineIndex, allLines, publicMethods, protectedMethods, privateMethods);
                    publicMethods.add(new JavaMethodInfo(methodMatcher.group(1), lineIndex, -1));
                    lastMethodType = 1;
                }

                // 检查保护方法
                methodMatcher = protectedMethodPattern.matcher(line);
                if (methodMatcher.find()) {
                    setLastMethodEndLine(lastMethodType, lineIndex, allLines, publicMethods, protectedMethods, privateMethods);
                    protectedMethods.add(new JavaMethodInfo(methodMatcher.group(1), lineIndex, -1));
                    lastMethodType = 2;
                }

                // 检查私有方法
                methodMatcher = privateMethodPattern.matcher(line);
                if (methodMatcher.find()) {
                    setLastMethodEndLine(lastMethodType, lineIndex, allLines, publicMethods, protectedMethods, privateMethods);
                    privateMethods.add(new JavaMethodInfo(methodMatcher.group(1), lineIndex, -1));
                    lastMethodType = 3;
                }
            }

            // 查找完全部行，设置最后一个方法的结束行
            if (lastMethodType > 0) {
                setLastMethodEndLine(lastMethodType, lineIndex, allLines, publicMethods, protectedMethods, privateMethods);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 返回解析结果
        return new JavaFileInfo(packageName, className, superclass, totalLine, publicMethods, protectedMethods, privateMethods);
    }

    /**
     * description: 设置上一个方法的结束行
     * @author: feng_jun_peng
     * @create: 2024-12-19 09:55
     * @param lastMethodType: 上一个匹配到的方法类型
     * @param nowLineIndex: 当前行号
     * @param lines: 读取出来的代码行
     * @param publicMethods: 公有方法
     * @param protectedMethods: 保护方法
     * @param privateMethods: 私有方法
     * @return: void
     */
    private static void setLastMethodEndLine(int lastMethodType, int nowLineIndex, List<String> lines, List<JavaMethodInfo> publicMethods, List<JavaMethodInfo> protectedMethods, List<JavaMethodInfo> privateMethods) {
        if (lastMethodType > 0) {
            // 上次已经匹配到方法，尝试找上次方法最后的 } 行号
            int startLine = -1;
            switch (lastMethodType) {
                case 1:
                    startLine = publicMethods.get(publicMethods.size() - 1).getStartLine();
                    break;
                case 2:
                    startLine = protectedMethods.get(protectedMethods.size() - 1).getStartLine();
                    break;
                case 3:
                    startLine = privateMethods.get(privateMethods.size() - 1).getStartLine();
                    break;
            }

            var endLine = nowLineIndex - 1;
            var isEnd = nowLineIndex == lines.size() - 1; //最后一行，则应该跳过一次 } 号
            if (isEnd)
                endLine = nowLineIndex; //最后一行，无须提前减去一行

            for (; endLine > startLine; endLine--) {
                var line = lines.get(endLine);
                if (line == null)
                    continue;
                if ("}".equals(line.trim().replace("\t", ""))) {
                    // 找到上次结束的行号
                    if (isEnd) {
                        isEnd = false;
                        continue;
                    }
                    break;
                }
            }

            switch (lastMethodType) {
                case 1:
                    publicMethods.get(publicMethods.size() - 1).setEndLine(endLine);
                    break;
                case 2:
                    protectedMethods.get(protectedMethods.size() - 1).setEndLine(endLine);
                    break;
                case 3:
                    privateMethods.get(privateMethods.size() - 1).setEndLine(endLine);
                    break;
            }
        }


    }
}
